package org.bdware.sc.node;

import com.google.gson.JsonElement;
import org.bdware.sc.bean.JoinInfo;
import org.bdware.sc.bean.RouteInfo;

import java.util.*;

public class FunctionNode extends Script {
    private final Set<String> dependentFunctions;
    private final List<AnnotationHook> beforeInvoke;
    private final List<AnnotationHook> afterInvoke;
    public String functionName;
    public List<AnnotationNode> annotations;
    boolean isStatic;
    List<Object> stmts;
    List<String> args;
    String fileName;
    boolean isExport;
    boolean isMask;
    //    boolean isLogLocally;
    EnumSet<LogType> logTypes;
    //    boolean logToChain;
    LogLocation logLocation = new LogLocation();
    private CostDetail cost;
    private RouteInfo routeInfo;
    private JoinInfo joinInfo;
    private boolean isHandler;
    private boolean isConfidential;
    private boolean isHomomorphicEncrypt;
    private boolean isHomomorphicDecrypt;
    private boolean isView;
    private String keyManagerID;
    private String secretID;
    private JsonElement homoEncryptConf;
    private JsonElement homoDecryptConf;

    public FunctionNode(String name, String fileName) {
        this.functionName = name;
        this.stmts = new ArrayList<>();
        this.args = new ArrayList<>();
        this.fileName = fileName;
        this.isExport = false;

        this.annotations = new ArrayList<>();
        this.dependentFunctions = new HashSet<>();
        this.logTypes = EnumSet.noneOf(LogType.class);
        this.isMask = false;
        this.isConfidential = false;
        this.isHomomorphicEncrypt = false;
        this.isHomomorphicDecrypt = false;
        this.isView = false;
        this.keyManagerID = "";
        this.secretID = "";

        beforeInvoke = new ArrayList<>();
        afterInvoke = new ArrayList<>();
    }

    public Set<String> getDependentFunctions() {
        return dependentFunctions;
    }

    public void addDependentFunctions(String functionName) {
        dependentFunctions.add(functionName);
    }

    public boolean isConfidential() {
        return isConfidential;
    }

    public void setConfidential(boolean isConfidential) {
        this.isConfidential = isConfidential;
    }

    public boolean isHandler() {
        return isHandler;
    }

    public void setHandler(boolean handler) {
        isHandler = handler;
    }

    public CostDetail getCost() {
        return cost;
    }

    public void setCost(CostDetail cost) {
        this.cost = cost;
    }

    public void setIsExport(boolean b) {
        isExport = b;
    }

    public void setIsMask(boolean b) {
        isMask = b;
    }

    public void setStatic(boolean b) {
        isStatic = b;
    }

    public void addArg(String arg) {
        args.add(arg);
        if (arg.equals("requester")) {
            throw new IllegalArgumentException("The argument shouldn't be requester");
        }
    }

    public void addStmt(StmtNode node) {
        stmts.add(node);
    }

    public void addStmts(List<StmtNode> l) {
        stmts.addAll(l);
    }

    public String getFileName() {
        return fileName;
    }

    public boolean isExport() {
        return isExport;
    }

    public boolean isMask() {
        return isMask;
    }

    public void initTextWithRequester() {
        if (args.size() == 0) {
            plainText = plainText.replaceFirst("\\)", "arg, requester, requesterDOI)");
        } else {
            plainText = plainText.replaceFirst("\\)", ", requester, requesterDOI)");
        }
    }

    public void addAnnotation(AnnotationNode annNode) {
        annotations.add(annNode);
    }

    public void addLogType(LogType v) {
        if (v == null) {
            return;
        }
        logTypes.add(v);
    }

    public EnumSet<LogType> getLogTypes() {
        return logTypes;
    }

    public boolean getLogToBDContract() {
        return logLocation.logToBDContract;
    }

    public void setLogToBDContract(boolean b) {
        logLocation.logToBDContract = b;
    }

    public boolean getLogToNamedLedger() {
        return logLocation.logToNamedLedger;
    }

    public void setLogToNamedLedger(boolean b) {
        logLocation.logToNamedLedger = b;
    }

    public void addLedgerName(String name) {
        if (logLocation.ledgerNames == null) {
            logLocation.ledgerNames = new ArrayList<>();
        }
        logLocation.ledgerNames.add(name);
    }

    public List<String> getLedgerNames() {
        return logLocation.ledgerNames;
    }

    public void appendAfterInvokeHandler(AnnotationHook handler) {
        afterInvoke.add(handler);
    }

    public List<AnnotationHook> afterExecutionAnnotations() {
        return afterInvoke;
    }

    public void appendBeforeInvokeHandler(AnnotationHook handler) {
        beforeInvoke.add(handler);
    }

    public List<AnnotationHook> beforeExecutionAnnotations() {
        return beforeInvoke;
    }

    public RouteInfo getRouteInfo() {
        return routeInfo;
    }

    public void setRouteInfo(RouteInfo routeInfo) {
        this.routeInfo = routeInfo;
    }

    public boolean isHomomorphicEncrypt() {
        return isHomomorphicEncrypt;
    }

    public void setHomomorphicEncrypt(boolean isHomomorphicEncrypt) {
        this.isHomomorphicEncrypt = isHomomorphicEncrypt;
    }

    public boolean isHomomorphicDecrypt() {
        return isHomomorphicDecrypt;
    }

    public void setHomomorphicDecrypt(boolean isHomomorphicDecrypt) {
        this.isHomomorphicDecrypt = isHomomorphicDecrypt;
    }

    public boolean isView() {
        return isView;
    }

    public void setView(boolean view) {
        isView = view;
    }

    public String getKeyManagerID() {
        return keyManagerID;
    }

    public void setKeyManagerID(String keyManagerID) {
        this.keyManagerID = keyManagerID;
    }

    public String getSecretID() {
        return secretID;
    }

    public void setSecretID(String secretID) {
        this.secretID = secretID;
    }

    public JoinInfo getJoinInfo() {
        return this.joinInfo;
    }

    public void setJoinInfo(JoinInfo joinInfo1) {
        this.joinInfo = joinInfo1;
    }

    public JsonElement getHomoEncryptConf() {
        return homoEncryptConf;
    }

    public void setHomoEncryptConf(JsonElement homoEncryptConf) {
        this.homoEncryptConf = homoEncryptConf;
    }

    public JsonElement getHomoDecryptConf() {
        return homoDecryptConf;
    }

    public void setHomoDecryptConf(JsonElement homoDecryptConf) {
        this.homoDecryptConf = homoDecryptConf;
    }
}
